home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / programming / libraries / newiff.lha / NewIFF / NewIFF39.lha / newiff39 / modules / ilbmr.c < prev    next >
C/C++ Source or Header  |  1993-09-28  |  16KB  |  536 lines

  1. /* ilbmr.c --- ILBM loading routines for use with iffparse */
  2.  
  3. /*----------------------------------------------------------------------*
  4.  * ILBMR.C  Support routines for reading ILBM files.
  5.  * (IFF is Interchange Format File.)
  6.  *
  7.  * Based on code by Jerry Morrison and Steve Shaw, Electronic Arts.
  8.  * This software is in the public domain.
  9.  * Modified for iffparse.library 05/90
  10.  * This version for the Commodore-Amiga computer.
  11.  *
  12.  * 37.9 04/92
  13.  * 39.1 07/92 - add setcolors() and support for V39 color loading
  14.  * 39.2 09/92 - only check AllShifted for colors that are used.
  15.  * 39.3 09/92 - obey CMAPOK advisories
  16.  * 39.4 09/92 - fix CMAPOK code (39.3 bug was ignoring colors if bit set)
  17.  * 39.5 11/92 - add GetBitMapAttr/destWidthBytes check
  18.  * 39.7  1/93 - clear modeid before calculating one for bad/missing camg
  19.  *----------------------------------------------------------------------*/
  20.  
  21. #define INTUI_V36_NAMES_ONLY
  22.  
  23. #include "iffp/ilbm.h"
  24. #include "iffp/packer.h"
  25. #include "iffp/ilbmapp.h"
  26.  
  27. #define movmem CopyMem
  28.  
  29. #define MaxSrcPlanes (25)
  30.  
  31. extern struct Library *GfxBase;
  32.  
  33. /*---------- loadbody ---------------------------------------------------*/
  34.  
  35. LONG loadbody(iff, bitmap, bmhd)
  36. struct IFFHandle *iff;
  37. struct BitMap *bitmap;
  38. BitMapHeader *bmhd;
  39.     {
  40.     BYTE *buffer;
  41.     ULONG bufsize;
  42.     LONG error = 1;
  43.  
  44.     D(bug("In loadbody\n"));
  45.  
  46.     if(!(currentchunkis(iff,ID_ILBM,ID_BODY)))
  47.         {
  48.         message(SI(MSG_ILBM_NOBODY));    /* Maybe it's a palette */
  49.         return(IFF_OKAY);
  50.         }
  51.  
  52.     if((bitmap)&&(bmhd))
  53.         {
  54.         D(bug("Have bitmap and bmhd\n"));
  55.  
  56.         bufsize = MaxPackedSize(RowBytes(bmhd->w)) << 4;
  57.             if(!(buffer = AllocMem(bufsize,0L)))
  58.         {
  59.         D(bug("Buffer alloc of %ld failed\n",bufsize));
  60.         return(IFFERR_NOMEM);
  61.         }
  62.         error = loadbody2(iff, bitmap, NULL, bmhd, buffer, bufsize);
  63.         D(bug("Returned from loadbody2, error = %ld\n",error));
  64.         }
  65.     FreeMem(buffer,bufsize);
  66.     return(error);
  67.     }
  68.  
  69.  
  70. /* like the old GetBODY */
  71. LONG loadbody2(iff, bitmap, mask, bmhd, buffer, bufsize)
  72. struct IFFHandle *iff;
  73. struct BitMap *bitmap;
  74. BYTE *mask;
  75. BitMapHeader *bmhd;
  76. BYTE *buffer;
  77. ULONG bufsize;
  78.    {
  79.    UBYTE srcPlaneCnt = bmhd->nPlanes;   /* Haven't counted for mask plane yet*/
  80.    WORD srcRowBytes = RowBytes(bmhd->w);
  81.    WORD destRowBytes = bitmap->BytesPerRow;   /* used as a modulo only */
  82.    LONG bufRowBytes = MaxPackedSize(srcRowBytes);
  83.    int nRows = bmhd->h;
  84.    WORD destWidthBytes;            /* used for width check */
  85.    WORD compression = bmhd->compression;
  86.    register int iPlane, iRow, nEmpty;
  87.    register WORD nFilled;
  88.    BYTE *buf, *nullDest, *nullBuf, **pDest;
  89.    BYTE *planes[MaxSrcPlanes]; /* array of ptrs to planes & mask */
  90.    struct ContextNode *cn;
  91.  
  92.    D(bug("loadbody2: srcRowBytes = %ld\n",srcRowBytes));
  93.  
  94.    cn = CurrentChunk(iff);
  95.  
  96.    if (compression > cmpByteRun1)
  97.       return(CLIENT_ERROR);
  98.  
  99.    /* If >=V39, this may be an interleaved bitmap with a BytesPerRow
  100.     * which is truly just a modulo and actually includes ALL planes.
  101.     * So instead, for bounds checking, we use the pixel width of
  102.     * the BitMap rounded up to nearest WORD, since saved ILBMs
  103.     * are always saved as their width rounded up to nearest WORD.
  104.     */
  105.    if(GfxBase->lib_Version >= 39)
  106.     {
  107.     destWidthBytes = RowBytes(GetBitMapAttr(bitmap,BMA_WIDTH));
  108.     }
  109.    else destWidthBytes = destRowBytes;
  110.  
  111.    D(bug("loadbody2: compression=%ld srcBytes=%ld bitmapBytes=%ld\n",
  112.         compression, srcRowBytes, bitmap->BytesPerRow));
  113.    D(bug("loadbody2: bufsize=%ld bufRowBytes=%ld, srcPlaneCnt=%ld\n",
  114.             bufsize, bufRowBytes, srcPlaneCnt));
  115.  
  116.    /* Complain if client asked for a conversion GetBODY doesn't handle.*/
  117.    if ( srcRowBytes  >  destWidthBytes  ||
  118.          bufsize < bufRowBytes * 2  ||
  119.          srcPlaneCnt > MaxSrcPlanes )
  120.       return(CLIENT_ERROR);
  121.  
  122.    D(bug("loadbody2: past conversion checks\n"));
  123.  
  124.    if (nRows > bitmap->Rows)   nRows = bitmap->Rows;
  125.  
  126.    D(bug("loadbody2: srcRowBytes=%ld, srcRows=%ld, srcDepth=%ld, destDepth=%ld\n",
  127.         srcRowBytes, nRows, bmhd->nPlanes, bitmap->Depth));
  128.    
  129.    /* Initialize array "planes" with bitmap ptrs; NULL in empty slots.*/
  130.    for (iPlane = 0; iPlane < bitmap->Depth; iPlane++)
  131.       planes[iPlane] = (BYTE *)bitmap->Planes[iPlane];
  132.    for ( ;  iPlane < MaxSrcPlanes;  iPlane++)
  133.       planes[iPlane] = NULL;
  134.  
  135.    /* Copy any mask plane ptr into corresponding "planes" slot.*/
  136.    if (bmhd->masking == mskHasMask)
  137.     {
  138.           if (mask != NULL)
  139.              planes[srcPlaneCnt] = mask;  /* If there are more srcPlanes than
  140.                * dstPlanes, there will be NULL plane-pointers before this.*/
  141.           else
  142.              planes[srcPlaneCnt] = NULL;  /* In case more dstPlanes than src.*/
  143.           srcPlaneCnt += 1;  /* Include mask plane in count.*/
  144.           }
  145.  
  146.    /* Setup a sink for dummy destination of rows from unwanted planes.*/
  147.    nullDest = buffer;
  148.    buffer  += srcRowBytes;
  149.    bufsize -= srcRowBytes;
  150.  
  151.    /* Read the BODY contents into client's bitmap.
  152.     * De-interleave planes and decompress rows.
  153.     * MODIFIES: Last iteration modifies bufsize.*/
  154.  
  155.    buf = buffer + bufsize;  /* Buffer is currently empty.*/
  156.    for (iRow = nRows; iRow > 0; iRow--)
  157.     {
  158.           for (iPlane = 0; iPlane < srcPlaneCnt; iPlane++)
  159.         {
  160.          pDest = &planes[iPlane];
  161.  
  162.             /* Establish a sink for any unwanted plane.*/
  163.             if (*pDest == NULL)
  164.         {
  165.             nullBuf = nullDest;
  166.                 pDest   = &nullBuf;
  167.                 }
  168.  
  169.             /* Read in at least enough bytes to uncompress next row.*/
  170.             nEmpty  = buf - buffer;      /* size of empty part of buffer.*/
  171.             nFilled = bufsize - nEmpty;      /* this part has data.*/
  172.         if (nFilled < bufRowBytes)
  173.         {
  174.             /* Need to read more.*/
  175.  
  176.             /* Move the existing data to the front of the buffer.*/
  177.             /* Now covers range buffer[0]..buffer[nFilled-1].*/
  178.                 movmem(buf, buffer, nFilled);  /* Could be moving 0 bytes.*/
  179.  
  180.                 if(nEmpty > ChunkMoreBytes(cn))
  181.             {
  182.                        /* There aren't enough bytes left to fill the buffer.*/
  183.                        nEmpty = ChunkMoreBytes(cn);
  184.                        bufsize = nFilled + nEmpty;  /* heh-heh */
  185.                        }
  186.  
  187.             /* Append new data to the existing data.*/
  188.                 if(ReadChunkBytes(iff, &buffer[nFilled], nEmpty) < nEmpty)
  189.             return(CLIENT_ERROR);
  190.  
  191.                 buf     = buffer;
  192.             nFilled = bufsize;
  193.             nEmpty  = 0;
  194.             }
  195.  
  196.          /* Copy uncompressed row to destination plane.*/
  197.             if(compression == cmpNone)
  198.         {
  199.                 if(nFilled < srcRowBytes)  return(IFFERR_MANGLED);
  200.             movmem(buf, *pDest, srcRowBytes);
  201.             buf    += srcRowBytes;
  202.                 *pDest += destRowBytes;
  203.                 }
  204.         else
  205.         {
  206.              /* Decompress row to destination plane.*/
  207.                 if ( unpackrow(&buf, pDest, nFilled,  srcRowBytes) )
  208.                     /*  pSource, pDest, srcBytes, dstBytes  */
  209.                        return(IFFERR_MANGLED);
  210.             else *pDest += (destRowBytes - srcRowBytes);
  211.         }
  212.         }
  213.     }
  214.    return(IFF_OKAY);
  215.    }
  216.  
  217.  
  218. /* ----------- getcolors ------------- */
  219.  
  220. /* getcolors - allocates a ilbm->colortable for at least 32 registers
  221.  *      and loads CMAP colors into it, setting ilbm->ncolors to number
  222.  *      of colors actually loaded.
  223.  *
  224.  * V39 and above: unless ilbm->IFFPFlags & IFFPF_NOCOLOR32, will also
  225.  *  allocate and build a 32-bit per gun colortable (ilbm->colortable32)
  226.  *  and ilbm->colorrecord for LoadRGB32().  
  227.  */
  228.  
  229. LONG getcolors(struct ILBMInfo *ilbm)
  230.     {
  231.     struct IFFHandle    *iff;
  232.     LONG error;
  233.  
  234.     if(!(iff=ilbm->ParseInfo.iff))    return(CLIENT_ERROR);
  235.  
  236.     if(!(error = alloccolortable(ilbm)))
  237.        error = loadcmap(ilbm);
  238.     if(error) freecolors(ilbm);
  239.     D(bug("getcolors: error = %ld\n",error));
  240.     return(error);
  241.     }
  242.  
  243.  
  244. /* alloccolortable - allocates ilbm->colortable and sets ilbm->ncolors
  245.  *    to the number of colors we have room for in the table.
  246.  *
  247.  * V39 and above: unless ilbm->IFFPFlags & IFFPF_NOCOLOR32, will also
  248.  *  allocate and build a 32-bit per gun colortable (ilbm->colortable32)
  249.  *  and ilbm->colorrecord for LoadRGB32()
  250.  */ 
  251.  
  252. LONG alloccolortable(struct ILBMInfo *ilbm)
  253.     {
  254.     struct IFFHandle    *iff;
  255.     struct    StoredProperty    *sp;
  256.  
  257.     LONG    error = CLIENT_ERROR;
  258.     ULONG    ctabsize;
  259.     USHORT    ncolors;
  260.  
  261.     if(!(iff=ilbm->ParseInfo.iff))    return(CLIENT_ERROR);
  262.  
  263.     if(sp = FindProp (iff, ID_ILBM, ID_CMAP))
  264.         {
  265.         /*
  266.          * Compute the size table we need
  267.          */
  268.         ncolors = sp->sp_Size / 3;        /* how many in CMAP */
  269.         ncolors = MAX(ncolors, 32);        /* alloc at least 32 */
  270.  
  271.         ctabsize = ncolors * sizeof(Color4);
  272.         if(ilbm->colortable = 
  273.            (Color4 *)AllocMem(ctabsize,MEMF_CLEAR|MEMF_PUBLIC))
  274.             {
  275.             ilbm->ncolors = ncolors;
  276.             ilbm->ctabsize = ctabsize;
  277.             error = 0L;
  278.  
  279.             if((GfxBase->lib_Version >= 39)&&
  280.                 (!(ilbm->IFFPFlags & IFFPF_NOCOLOR32)))
  281.             {
  282.             ctabsize = (ncolors * sizeof(Color32))+(4 * sizeof(WORD));
  283.             if(ilbm->colorrecord = (WORD *) 
  284.                   AllocMem(ctabsize,MEMF_CLEAR|MEMF_PUBLIC))
  285.                 {
  286.                 ilbm->crecsize = ctabsize; 
  287.                 ilbm->colortable32 = (Color32 *)(&ilbm->colorrecord[2]);
  288.                 ilbm->colorrecord[0] = ncolors;    /* For LoadRGB32 */
  289.                 ilbm->colorrecord[1] = 0;
  290.                 }
  291.             else error = IFFERR_NOMEM;
  292.             }
  293.             }
  294.         else error = IFFERR_NOMEM;
  295.         }
  296.     D(bug("alloccolortable for %ld colors: error = %ld\n",ncolors,error));
  297.  
  298.     if(error)    freecolors(ilbm);
  299.     return(error);
  300.     }
  301.  
  302.  
  303. void freecolors(struct ILBMInfo *ilbm)
  304.     {
  305.     if(ilbm->colortable)
  306.         {
  307.         FreeMem(ilbm->colortable, ilbm->ctabsize);
  308.         }
  309.     ilbm->colortable = NULL;
  310.     ilbm->ctabsize = 0;
  311.  
  312.     if(ilbm->colorrecord)
  313.         {
  314.         FreeMem(ilbm->colorrecord, ilbm->crecsize);
  315.         }
  316.     ilbm->colorrecord  = NULL;
  317.     ilbm->colortable32 = NULL;
  318.     ilbm->crecsize = 0;
  319.     }
  320.  
  321.  
  322.  
  323. /* loadcmap - note interface change for V39
  324.  *
  325.  * Passed ILBMInfo
  326.  *
  327.  * Sets ncolors (and colorrecord if using it) to the number actually read.
  328.  *
  329.  *  New for V39 and above: If bmhd->flags BMHDF_CMAPOK is set,
  330.  *  or if ILBMInfo->IFFPFlags IFFPF_CMAPOK is set, the 32-bit gun code
  331.  *  will assume the CMAP contains 8-bit significant guns (R,G,B)
  332.  *  and will not scale apparent 4-bit nibbles to 8 bits prior to
  333.  *  scaling to 32 bits.  In the absence of either of these flags,
  334.  *  if whole usable CMAP contains RGB values whose low nibbles are all 0,
  335.  *  this code will first scale the RGB values to 8 bits ($30 becomes $33, etc)
  336.  */ 
  337.  
  338. LONG loadcmap(struct ILBMInfo *ilbm)
  339.     {
  340.     struct StoredProperty    *sp;
  341.     LONG            k;
  342.     ULONG            ncolors, gun, ncheck;
  343.     UBYTE            *rgb, rb, gb, bb;
  344.     ULONG            nc, r, g, b;
  345.     struct IFFHandle    *iff;
  346.     BOOL AllShifted;
  347.  
  348.  
  349.     if(!(iff=ilbm->ParseInfo.iff))    return(CLIENT_ERROR);
  350.  
  351.     if(!(ilbm->colortable))
  352.     {
  353.     message(SI(MSG_ILBM_NOCOLORS));
  354.     return(1);
  355.     }
  356.  
  357.     if(!(sp = FindProp (iff, ID_ILBM, ID_CMAP)))    return(1);
  358.  
  359.  
  360.     rgb = sp->sp_Data;
  361.  
  362.     /* file has this many colors */
  363.     nc = sp->sp_Size / sizeofColorRegister;
  364.     ncolors = nc;
  365.  
  366.     /* if ILBMInfo can't hold that many, we'll load less */
  367.     if(ilbm->ncolors < ncolors)    ncolors = ilbm->ncolors;
  368.     /* set to how many we are loading */
  369.     ilbm->ncolors = ncolors;
  370.  
  371.     /* how many colors to check for shifted nibbles (i.e. used colors) */
  372.     ncheck = 1 << ilbm->Bmhd.nPlanes;
  373.     if(ncheck > ncolors) ncheck = ncolors;
  374.  
  375.     if((GfxBase->lib_Version >= 39)
  376.         && (!(ilbm->IFFPFlags & IFFPF_NOCOLOR32))
  377.             &&(ilbm->colorrecord))
  378.     {
  379.     ilbm->colorrecord[0] = ncolors;
  380.  
  381.     /* Assign to 32-bit table, examine for all-shifted nibbles at same time */
  382.     AllShifted = TRUE;
  383.     k = 0;
  384.         while (ncheck--) 
  385.             {
  386.             ilbm->colortable32[k].r = rb = *rgb++;
  387.             ilbm->colortable32[k].g = gb = *rgb++;
  388.             ilbm->colortable32[k].b = bb = *rgb++;
  389.         if(((rb & 0x0F) || (gb & 0x0F) || (bb & 0x0F)))
  390.             AllShifted=FALSE;
  391.             k++;
  392.             }
  393.  
  394.     /* If no file/user indication that this is an 8-bit significant CMAP... */
  395.     if( (!(ilbm->IFFPFlags & IFFPF_CMAPOK)) &&
  396.         (!(ilbm->Bmhd.flags & BMHDF_CMAPOK)) )
  397.         {
  398.         /* If all nibbles appear shifted (4 bit), duplicate the nibbles */
  399.         if(AllShifted)
  400.             {
  401.             for(k = 0; k <nc; k++)
  402.             {
  403.             ilbm->colortable32[k].r |= (ilbm->colortable32[k].r >> 4);
  404.             ilbm->colortable32[k].g |= (ilbm->colortable32[k].g >> 4);
  405.             ilbm->colortable32[k].b |= (ilbm->colortable32[k].b >> 4);
  406.             }
  407.         }
  408.         }
  409.  
  410.     /* Now scale to 32 bits */
  411.     for(k = 0; k <nc; k++)
  412.         {
  413.         gun = ilbm->colortable32[k].r;
  414.         ilbm->colortable32[k].r |= ((gun << 24) | (gun << 16) | (gun << 8));
  415.         gun = ilbm->colortable32[k].g;
  416.         ilbm->colortable32[k].g |= ((gun << 24) | (gun << 16) | (gun << 8));
  417.         gun = ilbm->colortable32[k].b;
  418.         ilbm->colortable32[k].b |= ((gun << 24) | (gun << 16) | (gun << 8));
  419.         }
  420.     }
  421.  
  422.     /* always make old-style table */
  423.     rgb = sp->sp_Data;
  424.     ncolors = nc;
  425.     k = 0;
  426.     while (ncolors--) 
  427.          {
  428.          r = (*rgb++ & 0xF0) << 4;
  429.          g = *rgb++ & 0xF0;
  430.          b = *rgb++ >> 4;
  431.          ilbm->colortable[k] = r | g | b;
  432.          k++;
  433.          }
  434.     return(0);
  435.     }
  436.  
  437.  
  438. /* setcolors - sets vp to ilbm->colortable or ilbm->colortable32
  439.  *
  440.  * V39 and above: unless ilbm->IFFPFlags & IFFPF_NOCOLOR32, will
  441.  *  use 32-bit per gun colortable (ilbm->colortable32) and functions
  442.  *
  443.  * Returns client error if there is no ilbm->vp
  444.  */ 
  445. LONG setcolors(struct ILBMInfo *ilbm, struct ViewPort *vp)
  446.     {
  447.     LONG nc;
  448.     LONG error = 0L;
  449.  
  450.     if(!(vp))    return(CLIENT_ERROR);
  451.  
  452.     nc = MIN(ilbm->ncolors,vp->ColorMap->Count);
  453.     if((GfxBase->lib_Version >= 39)&&
  454.         (! (ilbm->IFFPFlags & IFFPF_NOCOLOR32))&&
  455.             (ilbm->colorrecord))
  456.      {
  457.     LoadRGB32(vp, (ULONG *)ilbm->colorrecord);
  458.     }
  459.     else if(ilbm->colortable)
  460.     {
  461.     LoadRGB4(vp, ilbm->colortable, nc);
  462.     }
  463.     error = CLIENT_ERROR;
  464.     return(error);
  465.     }
  466.  
  467.  
  468. /*
  469.  * Returns CAMG or computed mode for storage in ilbm->camg
  470.  *
  471.  * ilbm->Bmhd structure must be initialized prior to this call.
  472.  */
  473. ULONG getcamg(struct ILBMInfo *ilbm)
  474.     {
  475.     struct IFFHandle *iff;
  476.     struct StoredProperty *sp;
  477.     UWORD  wide,high,deep;
  478.     ULONG modeid = 0L;
  479.  
  480.         if(!(iff=ilbm->ParseInfo.iff))    return(0L);
  481.  
  482.     wide = ilbm->Bmhd.pageWidth;
  483.     high = ilbm->Bmhd.pageHeight;
  484.     deep = ilbm->Bmhd.nPlanes;
  485.  
  486.     D(bug("Getting CAMG for pic w=%ld h=%ld d=%ld ILBM\n",wide,high,deep));
  487.  
  488.         /*
  489.          * Grab CAMG's idea of the viewmodes.
  490.          */
  491.         if (sp = FindProp (iff, ID_ILBM, ID_CAMG))
  492.                 {
  493.                 modeid = (* (ULONG *) sp->sp_Data);
  494.  
  495.         D(bug("Found CAMG containing $%08lx\n",modeid));
  496.  
  497.                 /* knock bad bits out of old-style 16-bit viewmode CAMGs
  498.                  */
  499.                 if((!(modeid & MONITOR_ID_MASK))||
  500.           ((modeid & EXTENDED_MODE)&&(!(modeid & 0xFFFF0000))))
  501.                    modeid &= 
  502.             (~(EXTENDED_MODE|SPRITES|GENLOCK_AUDIO|GENLOCK_VIDEO|VP_HIDE));
  503.  
  504.         D(bug("Filter1: CAMG now $%08lx\n",modeid));
  505.  
  506.                 /* check for bogus CAMG like DPaintII brushes
  507.                  * with junk in upper word and extended bit
  508.                  * not set in lower word.
  509.                  */
  510.                 if((modeid & 0xFFFF0000)&&(!(modeid & 0x00001000))) sp=NULL;
  511.  
  512.         D(bug("Filter2: CAMG is %s\n", sp ? "OK" : "NOT OK"));
  513.  
  514.                 }
  515.  
  516.         if(!sp) {
  517.                 /*
  518.                  * No CAMG (or bad CAMG) present; use computed modes.
  519.                  */
  520.         modeid = 0L;        /* added in 39.6 */
  521.                 if (wide >= 640)        modeid = HIRES;
  522.                 if (high >= 400)        modeid |= LACE;
  523.                 if (deep == 6)
  524.                         {
  525.                         modeid |= ilbm->EHB ? EXTRA_HALFBRITE : HAM;
  526.                         }
  527.         D(bug("No CAMG found - using mode $%08lx\n",modeid));
  528.                 }
  529.  
  530.     if(ilbm->IFFPFlags & IFFPF_NOMONITOR) modeid &= (~MONITOR_ID_MASK);
  531.  
  532.     D(bug("getcamg: modeid = $%08lx\n",modeid));
  533.     return(modeid);
  534.     }
  535.  
  536.